package org.dresdenocl.codegen.adapter; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import org.eclipse.emf.codegen.ecore.genmodel.GenClass; import org.eclipse.emf.codegen.ecore.genmodel.GenModel; import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EMap; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.resource.Resource; /** * Helper Class, mainly for naming conventions of the generated Pivot Model * adapters. * * @author Michael Thiele * */ public class PivotAdapterGeneratorUtil { // caches for all annotated elements ("PivotModel") and packages of all // classes in the DSL meta model private static Map<GenClass, String> dSL2PivotModel; private static Map<String, List<String>> pivotModel2DSL; private static Map<String, String> packageNames; private static List<EClass> allDSLTypes; private static String resourceName; private static String reservedKeywords[] = new String[] { "package", "class", "interface" }; private static String pivotModelTypes[] = new String[] { "Enumeration", "EnumerationLiteral", "Namespace", "Operation", "Parameter", "PrimitiveType", "Property", "Type" }; private PivotAdapterGeneratorUtil() { super(); } /** * Should be called before a new adapter generation. Deletes caches for * annotated elements and package names. */ public static void reset() { dSL2PivotModel = null; pivotModel2DSL = null; packageNames = null; allDSLTypes = null; resourceName = null; } public final static String TEMPLATE_LOCATION = PivotAdapterGeneratorPlugin.INSTANCE.getBaseURL().toString() + "templates"; public final static String CLASSPATH_VARIABLE_NAME = "TUDRESDEN_OCL20_PIVOT_ADAPTER"; /** * Returns the common super type of 2 <code>EClass</code>es. * * @param commonSuperType * the old common super type * @param dslType * the second type * @return the new common super type of the old common super type and the DSL * type */ protected static EClass getCommonSuperType(EClass commonSuperType, EClass dslType) { EList<EClass> allSuperTypes = dslType.getEAllSuperTypes(); if (commonSuperType.equals(dslType) || allSuperTypes.contains(commonSuperType)) return commonSuperType; // breadth first search in all super types of common super type Queue<EClass> queue = new LinkedList<EClass>(); queue.add(commonSuperType); while (!queue.isEmpty()) { EClass eClass = queue.poll(); EList<EClass> directSuperTypes = eClass.getESuperTypes(); for (EClass directSuperType : directSuperTypes) { if (allSuperTypes.contains(directSuperType)) return directSuperType; } queue.addAll(directSuperTypes); } // no match could be found, so EObject is the common super type return EcoreFactory.eINSTANCE.createEObject().eClass(); } /** * Determines the common superclass of all DSL types that are mapped to Pivot * Model types. * * @param genModel * @return the common superclass of the all DSL types */ public static String getCommonSuperType(GenModel genModel) { if (dSL2PivotModel == null) createAnnotatedElements(genModel); Iterator<GenClass> dslTypeIter = dSL2PivotModel.keySet().iterator(); EClass commonSuperType = null; // find the first common super type if (dslTypeIter.hasNext()) { GenClass dslTypeGenClass = dslTypeIter.next(); commonSuperType = dslTypeGenClass.getEcoreClass(); } else // no elements are annotated, so no common super type can be found return "Object"; while (dslTypeIter.hasNext()) { commonSuperType = getCommonSuperType(commonSuperType, dslTypeIter.next() .getEcoreClass()); if (commonSuperType.getName().equals("EObject")) { return "Object"; } } return genModel.findGenPackage(commonSuperType.getEPackage()) .getInterfacePackageName() + "." + commonSuperType.getName(); } /** * Computes the common super type for all DSL types that are mapped to the * Pivot Model Type type. * * @param genModel * @return the name of the common super type for all DSL <code>Type</code> * types. */ public static String getCommonSuperTypeForDSLTypes(GenModel genModel) { EClass commonSuperType; if (pivotModel2DSL == null) createAnnotatedElements(genModel); if (!allDSLTypes.isEmpty()) { Iterator<EClass> typesIter = allDSLTypes.iterator(); commonSuperType = typesIter.next(); while (typesIter.hasNext()) { commonSuperType = getCommonSuperType(commonSuperType, typesIter.next()); } return genModel.findGenPackage(commonSuperType.getEPackage()) .getInterfacePackageName() + "." + commonSuperType.getName(); } else return null; } /** * * @param genClass * @return the full package name of the genClass */ public static String getPackageNameFor(GenClass genClass) { return (genClass.getGenPackage().getInterfacePackageName() == null ? "" : genClass.getGenPackage().getInterfacePackageName() + "."); } /** * * @param annotation * @return a String representing the Pivot Model type that is mapped to */ protected static String getAnnotationDetails(EAnnotation annotation) { if (annotation.getSource().equalsIgnoreCase( "http://www.tu-dresden.de/ocl20/pivot/2007/pivotmodel")) { EMap<String, String> annotationDetails = annotation.getDetails(); if (annotationDetails != null) { if (annotationDetails.containsKey("PivotModel")) return annotationDetails.get("PivotModel"); if (annotationDetails.containsKey("Pivotmodel")) return annotationDetails.get("Pivotmodel"); if (annotationDetails.containsKey("pivotModel")) return annotationDetails.get("pivotModel"); if (annotationDetails.containsKey("pivotmodel")) return annotationDetails.get("pivotmodel"); } } return null; } protected static void createPackageNames(GenModel genModel) { packageNames = new HashMap<String, String>(); for (GenPackage genPackage : genModel.getGenPackages()) { getGenPackages(genPackage); } } private static void getGenPackages(GenPackage genPackage) { for (GenPackage subPackage : genPackage.getNestedGenPackages()) { getGenPackages(subPackage); } for (GenClass genClass : genPackage.getGenClasses()) { packageNames.put(genClass.getName(), (genPackage .getInterfacePackageName() == null ? "" : genPackage .getInterfacePackageName() + "." + genClass.getName())); } } /** * * @param genModel * @param genClassName * @return the genClass's package name + the genClass's name */ public static String getGenClassPackage(GenModel genModel, String genClassName) { // all package names are cached. if (packageNames == null) createPackageNames(genModel); if (packageNames.containsKey(genClassName)) return packageNames.get(genClassName); else return genClassName; } protected static void createAnnotatedElements(GenModel genModel) { dSL2PivotModel = new HashMap<GenClass, String>(); pivotModel2DSL = new HashMap<String, List<String>>(); allDSLTypes = new LinkedList<EClass>(); for (GenPackage genPackage : genModel.getGenPackages()) { getGenClasses(genPackage); } } private static void getGenClasses(GenPackage genPackage) { for (GenPackage subPackage : genPackage.getNestedGenPackages()) { getGenClasses(subPackage); } for (GenClass genClass : genPackage.getGenClasses()) { for (EAnnotation annotation : genClass.getEcoreClass().getEAnnotations()) { String pivotModelTypeName = getAnnotationDetails(annotation); if (pivotModelTypeName != null) { // fill maps for both mapping directions dSL2PivotModel.put(genClass, pivotModelTypeName); if (pivotModel2DSL.containsKey(pivotModelTypeName)) pivotModel2DSL.get(pivotModelTypeName).add(genClass.getName()); else pivotModel2DSL.put(pivotModelTypeName, new LinkedList<String>( Arrays.asList(genClass.getName()))); if (pivotModelTypeName.equals("Type") || pivotModelTypeName.equals("PrimitiveType") || pivotModelTypeName.equals("Enumeration")) allDSLTypes.add(genClass.getEcoreClass()); } } } } /** * Method tests if the DSL type name is unique. If not it generates an unique * name. * * @param genModel * the genModel of the DSL * @param genClass * the DSL type * @return a unique name of the DSL type that is mapped to a Pivot Model * element */ public static String getDSLModelUniqueTypeName(GenModel genModel, GenClass genClass) { // all annotated elements (DSL Type -> Pivot Model) are cached if (dSL2PivotModel == null) { createAnnotatedElements(genModel); } if (dSL2PivotModel.containsKey(genClass)) { // tests, if DSL type names equal Pivot Model elements -> to avoid // any confusion, the DSL types are used with full package name String dslModelTypeName = genClass.getName(); if (Arrays.asList(pivotModelTypes).contains(dslModelTypeName)) return getGenClassPackage(genModel, dslModelTypeName); else { // check whether the DSLs type name equals one of Java's // reserved // keywords -> full package name for (String keyword : reservedKeywords) { if (dslModelTypeName.equalsIgnoreCase(keyword)) return getGenClassPackage(genModel, dslModelTypeName); } return dslModelTypeName; } } else return null; } /** * Returns a <code>List</code> of (not necessarily unique) DSL type names for * a Pivot Model type (more than 1 DSL type can be mapped to a Pivot Model * type). * * @param genModel * the genModel of the DSL * @param givenPivotModelType * the Pivot Model type the DSL types are looked up for * @return a <code>List</code> of (not necessarily unique) DSL type names that * are mapped to the <code>pivotModelType</code> */ public static List<String> getDSLModelTypeNames(GenModel genModel, String givenPivotModelType) { if (pivotModel2DSL == null) createAnnotatedElements(genModel); /* * Since Type has subtypes PrimitiveType and Enumeration, also check for * them */ List<String> givenPivotModelTypes = new LinkedList<String>(); givenPivotModelTypes.add(givenPivotModelType); if (givenPivotModelType.equals("Type")) { givenPivotModelTypes.add("PrimitiveType"); givenPivotModelTypes.add("Enumeration"); } List<String> retList = new LinkedList<String>(); for (String pivotModelName : givenPivotModelTypes) { if (pivotModel2DSL.containsKey(pivotModelName)) retList.addAll(pivotModel2DSL.get(pivotModelName)); } return retList; } /** * Returns a <code>List</code> of unique DSL type names for a Pivot Model type * (more than 1 DSL type can be mapped to a Pivot Model Type). * * @param genModel * the genModel of the DSL * @param givenPivotModelType * the Pivot Model type the DSL types are looked up for * @return a <code>List</code> of unique DSL type names that are mapped to the * <code>pivotModelType</code> */ public static List<String> getDSLModelUniqueTypeNames(GenModel genModel, String givenPivotModelType) { if (pivotModel2DSL == null) createAnnotatedElements(genModel); /* * Since Type has subtypes PrimitiveType and Enumeration, also check for * them */ List<String> givenPivotModelTypes = new LinkedList<String>(); givenPivotModelTypes.add(givenPivotModelType); if (givenPivotModelType.equals("Type")) { givenPivotModelTypes.add("PrimitiveType"); givenPivotModelTypes.add("Enumeration"); } List<String> dslModelUniqueTypeNames = new LinkedList<String>(); for (String pivotModelType : givenPivotModelTypes) { if (pivotModel2DSL.containsKey(pivotModelType)) { // tests, if DSL type names equal Pivot Model elements -> to avoid // any confusion, the DSL types are used with full package name List<String> dslModelTypeNames = pivotModel2DSL.get(pivotModelType); for (String dslModelTypeName : dslModelTypeNames) { boolean withPackage = false; if (Arrays.asList(pivotModelTypes).contains(dslModelTypeName)) { dslModelUniqueTypeNames.add(getGenClassPackage(genModel, dslModelTypeName)); withPackage = true; } else { // check whether the DSLs type name equals one of Java's // reserved // keywords -> full package name for (String keyword : reservedKeywords) { if (dslModelTypeName.equalsIgnoreCase(keyword)) { dslModelUniqueTypeNames.add(getGenClassPackage(genModel, dslModelTypeName)); withPackage = true; break; } } } if (!withPackage) dslModelUniqueTypeNames.add(dslModelTypeName); } } } return dslModelUniqueTypeNames; } /** * * @param dslElement * the name of the DSL element * @return a name for this element that can be used without any naming * conflicts */ public static String getDSLElementName(String dslElement) { if (dslElement == null) return null; // test, if the name is one of the reserved keywords of Java for (String keyword : reservedKeywords) { if (dslElement.equalsIgnoreCase(keyword)) dslElement = "a" + startWithCapitalLetter(dslElement); } // if the DSL Type is used with package name in front of the class name, // skip the package name and put "dsl" in front of the name to // distinguish // from the Pivot Model namespace name if (dslElement.contains(".")) return "dsl" + dslElement.substring(dslElement.lastIndexOf(".") + 1, dslElement .length()); return PivotAdapterGeneratorUtil.startWithLowerCaseLetter(dslElement); } /** * * @return the String which is displayed for all methods that require * implementation */ public static String getImplementThis() { return "// TODO: implement this method" + System.getProperty("line.separator") + "\t\t" + "// don't forget to remove the @generated tag or change it to \"@generated NOT\""; } /** * * @param genModel * @param genClass * the DSL type * @return the name for the adapter class */ public static String getAdapterClassName(GenModel genModel, GenClass genClass) { return genModel.getModelName() + startWithCapitalLetter(genClass.getName()); } /** * * @param genModel * @param mappedType * the type name of the Pivot Model * @return */ public static String getAdapterClassName(GenModel genModel, String mappedType) { return genModel.getModelName() + startWithCapitalLetter(mappedType); } /** * Imports the adaptee's type declaration. * * @param genModel * @param genClass * @return the fully qualified location of the adaptee */ public static String getAdapteeClassImport(GenModel genModel, GenClass genClass) { String uniqueTypeName = getDSLModelUniqueTypeName(genModel, genClass); String packageName = getPackageNameFor(genClass); if (packageName.contains(".") && uniqueTypeName.contains(".")) return packageName + uniqueTypeName.substring(uniqueTypeName.lastIndexOf(".") + 1); else return packageName + uniqueTypeName; } /** * * @param typeName * @return */ public static String getTypeNameWithoutPackage(String typeName) { typeName = startWithLowerCaseLetter(typeName .substring(typeName.lastIndexOf(".") + 1)); if (Arrays.asList(reservedKeywords).contains(typeName)) typeName = "a" + startWithCapitalLetter(typeName); return typeName; } /** * Attention: projectName == packageName * * @param genModel * @return the project/package name */ public static String getProjectName(GenModel genModel) { return "org.dresdenocl.metamodels." + genModel.getModelName().toLowerCase(); } public static String startWithCapitalLetter(String string) { return string.substring(0, 1).toUpperCase() + string.substring(1); } public static String startWithLowerCaseLetter(String string) { return string.substring(0, 1).toLowerCase() + string.substring(1); } /** * * @param genModel * @return the package where all adapters are generated */ public static String getAdapterPackage(GenModel genModel) { return getProjectName(genModel) + ".internal.model"; } /** * * @param genModel * @return the package for the model provider */ public static String getProviderPackage(GenModel genModel) { return getProjectName(genModel) + ".internal.provider"; } /** * The user can define a mapping for the resource type. This is done via an * {@link EAnnotation} with the source set to * "http://www.tu-dresden.de/ocl20/pivot/2007/pivotmodel" and the * {@link EAnnotation#getDetails() details} set to "Resource" -> the fully * qualified name of the resource (e.g., {@link Resource * org.eclipse.emf.ecore.resource.Resource}) * * @param genModel * @return the fully qualified name of the resource or <code>null</code> if * not declared */ public static String getResourceType(GenModel genModel) { // search for the annotation, if not already determined if (resourceName != null) return resourceName; // only look in top-level packages for (GenPackage genPackage : genModel.getGenPackages()) { for (EAnnotation annotation : genPackage.getEcorePackage() .getEAnnotations()) { if (annotation.getSource().equalsIgnoreCase( "http://www.tu-dresden.de/ocl20/pivot/2007/pivotmodel")) { EMap<String, String> annotationDetails = annotation.getDetails(); if (annotationDetails != null) { if (annotationDetails.containsKey("Resource")) { final String resourceType = annotationDetails.get("Resource"); resourceName = resourceType; return resourceType; } // no else } // no else } // no else } // end iterate annotations } // end iterate genPackages return null; } }